const scrollParent = (el) => {
  let parent = el.parentNode;

  while (parent) {
    if (/scroll|auto/.test(getComputedStyle(parent)["overflow"])) {
      return parent;
    }
    parent = parent.parentNode;
    if (parent === Window) {
      return Document;
    }
  }
  return parent;
};
const throttle = (cb, delay = 0) => {
  let prev = Date.now();
  return () => {
    let now = Date.now();
    if (now - prev >= delay) {
      cb();
      prev = Date.now();
    }
  };
};
const Lazy = (Vue) => {
  const loadImageAsync = (src, resolve, reject) => {
    let image = new Image();
    image.src = src;
    image.onload = resolve;
    image.onerror = reject;
  };
  class ReactiveListener {
    constructor({ el, src, options }) {
      this.el = el;
      this.src = src;
      this.options = options;
      this.state = {
        loaded: false,
      };
    }
    checkInView() {
      let { top } = this.el.getBoundingClientRect();
      return top < window.innerHeight * this.options.preLoad;
    }
    load() {
      this.elRenderer(this, "loading");
      loadImageAsync(
        this.src,
        () => {
          this.state.loaded = true; // 加载完毕了
          this.elRenderer(this, "loaded");
        },
        () => {
          this.elRenderer(this, "error");
        }
      );
    }
    elRenderer(listener, state) {
      let el = listener.el;
      let src = "";
      switch (state) {
        case "loading":
          src = listener.options.loading || "";
          break;
        case "error":
          src = listener.options.error || "";
          break;
        default:
          src = listener.src;
          break;
      }
      el.setAttribute("src", src);
    }
  }
  return class LazyClass {
    constructor(options) {
      console.log(this);
      this.options = options;
      this.listenerQueue = [];
    }
    lazyLoadHandler() {
      this.listenerQueue.forEach((listener) => {
        if (listener.state.loaded) {
          return;
        }
        listener.checkInView() && listener.load();
      });
    }
    add(el, bindings) {
      Vue.nextTick(() => {
        // 获取滚动元素
        let parent = scrollParent(el);
        // 获取链接
        let src = bindings.value;
        const reactiveListener = new ReactiveListener({
          el,
          src,
          options: this.options,
        });
        reactiveListener.checkInView() && reactiveListener.load();
        this.listenerQueue.push(reactiveListener);
        parent.addEventListener(
          "scroll",
          throttle(this.lazyLoadHandler.bind(this),100)
        );
      });
    }
  };
};
let VueLazyLoad = {
  install(Vue, userOptions) {
    const LazyClass = Lazy(Vue);
    const lazy = new LazyClass(userOptions);
    Vue.directive("lazy", {
      bind: lazy.add.bind(lazy),
    });
  },
};

export default VueLazyLoad;
